Crate class_list_macro
source ·Expand description
class_list
A reactive helper that ensures normalized class list strings in frontend frameworks like Leptos.
Usage
Examples provided will be for the Leptos framework post-{context removal}, but it will work pre-{context removal} and might work in other similar frameworks.
This library is meant to be agnostic and has no runtime dependencies, but it has only been tested with Leptos.
cargo add class_list
Example
class_list![]
by default wraps itself in a move closure, meaning it will be reactive by default.
let (count, set_count) = create_signal(0);
set_interval(
move || {
set_count.update(|count| *count += 1);
},
Duration::from_millis(100),
);
let count_class = move || format!("count-{}", count());
let count_is_even = move || count() % 2 == 0;
view! {
<div class=class_list![
"default-class-names",
// Closures get called automatically.
count_class,
// Closures can be written directly into the macro.
move || format!("count-{}", count()),
// Both Option and Result can be used as values.
// None and Err result in no class name.
Some("option"),
None::<String>,
// More conveniently, class names can be bound to reactive toggles.
// "even" will only be applied when `count_is_even()` is true.
// You also don't need to call closures here.
"even" <=> count_is_even
] />
}
Options
Each option must be followed by a ;
.
Raw
To generate a non-reactive String, add the raw
option to the beginning.
class_list![
raw;
"default-class-names",
]
Clone
Rarely, you may need to clone something before passing it in.
The macro makes this easy with the clone
option which clones the variable before it gets moved into the closure.
If possible try to avoid needing this option in the first place.
class_list![
clone[count_class];
"default-class-names",
]
Crate
This should never be needed because it’s automatically supplied by a wrapper macro_rules!
.
In a case where the trait imports cannot be resolved–such as when used inside of another library–, the path can be redefined.
The path should lead to the root of this library.
__class_list![
crate = ::your_lib::class_list;
"default-class-names",
]
Implementing Traits
If you’d like to simply pass a type to the macro instead of converting it every time, you can implement the ClassList
and ClassToggle
types.
Check out traits.rs to see the default implementations which are good examples of implementing them.
// If you're using a type you don't own,
// you must wrap it in a new struct.
struct Bool(bool);
impl ClassList for Bool {
fn to_class_list(&self, normalize: bool) -> String {
// If the string could contain multiple class names
// you should use `normalize` to determine whether
// or not to call `.to_class_list()` on it before
// returning.
// If you're lazy you could always normalize, but
// then the string will be normalized multiple
// times for every update in the macro.
if self.0 {
"true".into()
} else {
"false".into()
}
}
}
impl ClassToggle for Bool {
fn to_class_toggle(&self) -> bool {
self.0
}
}
// Option, Result, and Fn are implemented in a way which
// allows any new type you implement to be automatically
// passed through.
assert_eq!(
class_list![
// ClassList
move || Bool(false),
Bool(true),
"class",
// ClassToggle
"hidden" <=> move || Bool(false),
"list",
](),
"false true class list".to_string()
);
Macros
- class_list